home *** CD-ROM | disk | FTP | other *** search
Text File | 2001-01-26 | 63.2 KB | 1,854 lines |
- ## -*-Tcl-*- (nowrap)
- # ==========================================================================
- # Statistical Modes - an extension package for Alpha
- #
- # FILE: "sMode.tcl"
- # created: 01/15/00 {07:15:32 pm}
- # last update: 01/26/01 {12:29:02 pm}
- # Description:
- #
- # For S (or S-Plus) syntax files, as well as the free distribution of R.
- #
- # Author: Craig Barton Upright
- # E-mail: <cupright@princeton.edu>
- # mail: Princeton University, Department of Sociology
- # Princeton, New Jersey 08544
- # www: <http://www.princeton.edu/~cupright>
- #
- # -------------------------------------------------------------------
- #
- # Copyright (c) 2000-2001 Craig Barton Upright
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- #
- # ==========================================================================
- ##
-
- # ===========================================================================
- #
- # ◊◊◊◊ Initialization of S mode ◊◊◊◊ #
- #
-
- alpha::mode S 2.1.1 sMenu {*.s *.S *.R} {
- sMenu electricReturn electricTab electricBraces
- } {
- # We require 7.4b21 for prefs handling.
- alpha::package require -loose AlphaTcl 7.4b21
- addMenu sMenu "S+/R" S
- set unixMode(splus) {S}
- } uninstall {
- catch {file delete [file join $HOME Tcl Modes sMode.tcl]}
- catch {file delete [file join $HOME Tcl Completions SCompletions.tcl]}
- catch {file delete [file join $HOME Tcl Completions "S Tutorial.s"]}
- } help {
- file "Statistical Modes Help"
- } maintainer {
- "Craig Barton Upright" <cupright@princeton.edu>
- <http://www.princeton.edu/~cupright/>
- }
-
- hook::register quitHook S::quitHook
-
- proc sMenu {} {}
-
- proc sMode.tcl {} {}
-
- namespace eval S {}
-
- # ===========================================================================
- #
- # ◊◊◊◊ Setting S mode variables ◊◊◊◊ #
- #
-
- # Removing obsolete preferences from earlier versions.
-
- set oldvars {
- don'tRemindMe funcExpr parseExpr keywordColor eitherorColor
- functionColor useMagicCharacter eitherOrs eitherOrColor sHelp
- }
-
- foreach oldvar $oldvars {prefs::removeObsolete SmodeVars($oldvar)}
-
- unset oldvar oldvars
-
- # ===========================================================================
- #
- # Standard preferences recognized by various Alpha procs
- #
-
- newPref var leftFillColumn {0} S
- newPref var fillColumn {75} S
- newPref var prefixString {# } S
- newPref var wordBreak {[-a-zA-Z0-9\._]+} S
- newPref var wordBreakPreface {[^-a-zA-Z0-9\._]} S
- newPref flag wordWrap {0} S
-
- # ===========================================================================
- #
- # Flag preferences
- #
-
- newPref flag autoMark {0} S {S::rebuildMenu markSFileAs}
-
- # By default command double-click will send a command to on-line help, and
- # option double-click sends a command to the local S-Plus application.
- # Check this box to switch these key combinations.
- newPref flag localHelp {0} S {S::rebuildMenu sMenu}
-
- # Check this box if your keyboard does not have a "Help" key. This will
- # change some of the menu's key bindings.
- newPref flag noHelpKey {0} S {S::rebuildMenu sMenu}
-
- # Check this preference to use Venable and Ripley's MASS library for keyword
- # colorizing and completions
- newPref flag useMassLibrary {1} S {S::colorizeS}
-
- # Set the list of flag preferences which can be changed in the menu.
-
- set SPrefsInMenu [list \
- "localHelp" \
- "noHelpKey" \
- "useMassLibrary" \
- ]
-
- # ===========================================================================
- #
- # Variable preferences
- #
-
- # Enter additional arguments to be colorized.
- newPref var addArguments {c dimnames list plot replace} S {S::colorizeS}
-
- # Enter additional S commands to be colorized.
- newPref var addCommands {print} S {S::colorizeS}
-
- # Select the statistical application to be used.
- newPref var application {S+} S {S::rebuildMenu sMenu} [list R S+]
-
- # Command double-clicking on an S keyword will send it to this url for a
- # help reference page.
- newPref url helpUrl {http://stat.ethz.ch/R-alpha/library/base/html/} S
-
- # The "R Home Page" menu item will send this url to your browser.
- newPref url rHomePage {http://cran.r-project.org/} S
-
- # Click on "Set" to find the local R application.
- newPref sig rSig {} S {}
-
- # The "S+ Home Page" menu item will send this url to your browser.
- newPref url s+HomePage {http://www.splus.mathsoft.com/} S
-
- # Click on "Set" to find the local S+ application. (As of this writing
- # there are no such applications for the Macintosh.)
- newPref sig s+Sig {} S {}
-
- # ===========================================================================
- #
- # Color preferences
- #
- # Nomenclature notes:
- #
- # S-Plus is remarkably elegant in structure. Commands have arguments, and
- # rarely does the language use the same names for both. There are a few
- # exceptions, listed initially in the argument category.
- #
-
- # See the Statistical Modes Help file for an explanation of these different
- # categories, and lists of keywords.
- newPref color argumentColor {magenta} S {S::colorizeS}
- newPref color commandColor {blue} S {S::colorizeS}
- newPref color commentColor {red} S {stringColorProc}
-
- # Color of the magic character $. Magic Characters will colorize any
- # string which follows them, up to the next empty space.
- newPref color magicColor {black} S {S::colorizeS}
-
- newPref color stringColor {green} S {stringColorProc}
-
- # The color of symbols such as "/", "@", etc.
- newPref color symbolColor {magenta} S {S::colorizeS}
-
- regModeKeywords -e {#} \
- -c $SmodeVars(commentColor) \
- -s $SmodeVars(stringColor) S {}
-
- # ===========================================================================
- #
- # Flag Flip
- #
- # Called by menu items, change the value of flag preferences.
- #
-
- proc S::flagFlip {pref} {
-
- global mode SmodeVars
-
- set SmodeVars($pref) [expr {$SmodeVars($pref) ? 0 : 1}]
- set oldMode $mode
- set mode "S"
- synchroniseModeVar $pref $SmodeVars($pref)
- set mode $oldMode
- if {$SmodeVars($pref)} {
- set end "on"
- } else {
- set end "off"
- }
- message "The \"$pref\" preference is now $end."
- }
-
- # ===========================================================================
- #
- # Comment Character variables for Comment Line / Paragraph / Box menu items.
- #
-
- set S::commentCharacters(General) "# "
- set S::commentCharacters(Paragraph) [list "## " " ##" " # "]
- set S::commentCharacters(Box) [list "#" 1 "#" 1 "#" 3]
-
- # ===========================================================================
- #
- # ◊◊◊◊ Keyword Dictionaries ◊◊◊◊ #
- #
-
- # Making sure that SUserCommands and SUserArguments exist.
- # These will be over-ridden if they are loaded from a ${mode}Prefs.tcl file.
- #
-
- set SUserCommands ""
- set SUserArguments ""
-
- # ===========================================================================
- #
- # ◊◊◊◊ S Commands ◊◊◊◊ #
- #
-
- set SCommands {
- abbreviate abline abs ace acf acf.plot adm.ave adm.filt adm.smo acos
- add1 aggregate aggregrate.ts agnes akima alias all all.equal allocated
- anova any aov aov.genyates aperm append apply approx ar ar.burg ar.gm
- ar.yw arg.dialog args arima.diag arima.filt arima.forecast
- arima.fracdiff arima.fracdiff.sim arima.mle arima.sim arima.td array
- arrows as.character as.data.frame as.data.frame.array as.data.frame.ts
- as.matrix as.numeric as.vector as.xxx asin assign atan attach attr
- attributes avas axis backsolve banking barchart barplot BATCH bcv
- binomial biplot biplot.default bootstrap boxplay browser brush bs
- butterfly bwplot by c cancor cat cbind cdf.compare ceiling cex
- character charmatch chissq.gof chol clara class close.screen cloud
- cmdscale coef coefficients contour countourplot contr.helmert
- contr.poly contr.sdif contr.sum contr.treatment contrasts cor cor.test
- correlogram cos cosh count.fields cov.mve cov.wt cox.zph coxph
- crossprod crosstabs cts cummax cummin cumprod cumsum cut cutree cv.tree
- D daisy data.class data.dump data.frame data.matrix data.restore
- database.object date dates dbwrite debugger demod density densityplot
- deparse deriv deriv3 design det detach dev.ask dev.copy dev.cur
- dev.list dev.next dev.off dev.prev dev.print dev.set deviance dget diag
- Diagonal diana diff dim dimnames dist dmvnorm do.call dos dos.time
- dotchart dotplot dput drop drop1 dummy.corf dump dump.calls dump.frames
- dumpdata duplicated ed eigen equal.count Error eval exists exp
- expand.grid expcov expn expression F fac/desogm faces factanal factor
- family fanny fft fig file.exists filter find .First .First.lib
- .First.local fitted fitted.values fix fixed.effects floor for format
- formula fpl fractionate frame frequency.polygram symbol gam gam.plot
- gamma gaucov gaussian get glm glm.links glm.variances graphics.off
- graphsheet grep hclust help help.off help.start hist hist.FD hist.scott
- hist2d histogram history hpgl hplg I() identify if ifelse Im image
- inspect integrate interaction.plot interp inverse.gaussian invisible
- iris4d is.characger is.na is.random is.xxx its julian Kaver keep.order
- Kenvl key Kfn kmeans kruskal.test ks.gof ksmooth l1fit lag lapply .Last
- last.dump .Last.value leaps legend length letters levelplot levels
- lgamma library limits.bca limits.emp lines list lm lm.influence lme
- lmsreg lo loadings location.m locator loess log log10 loglin lower.tri
- lowess ltsreg lu mad mahalanobis mai make.call make.family make.fileds
- make.groups manova mar masked mat2tr match match.arg matplot matrix
- Matrix.class max mclass mclust mean median memory.size merge mex mfcol
- mfrow min misclass.tree missing mkh mode model.frame.tree model.matrix
- model.tables mona monthplot motif mreloc ms mstree mtext multinom
- na.action na.fail na.gam.replace na.omit names nchar nclass.FD
- nclass.scott ncol neg.bin next NextMethod nlme nlminb nlregb nls
- nlsList nnet nnet.Hess nnls.fit norm nroff nrow ns ntrellis numeric
- as.design objdiff objects offset oma omd omi on.exit openlook optimize
- optimize options .Options order ordered outer output pairs pam par
- partition.tree paste pdf.graph persp persp.setup perspp pi pie piechart
- plclust plot.gam plot.survfit pltree pmatch pmax pmin pmvnorm pnorm
- points poisson poly polygon polyroot post.tree postscript ppinit pplik
- ppoints ppreg ppregion prcomp predict predict.factanal predict.gam
- predict.lm predict.lme predict.tree princomp print.summary
- print.trellis printgraph prmat proc.time prod profile proj prompt
- prompt.screen prune.misclass prune.tree Psim pty q qda qqline qqnorm
- qqplot qr qr.coef qr.fitted qr.Q qr.R qr.resid qr.X quantile quasi
- .Random.seed range rank raov rbind rbiwt rcond Re read.table Recall
- remove reorder.factor rep repeat replications resid residuals restart
- return rev rm rmv rmvnorm rnorm rotate rotate.default round row
- row.names RowPermutation Rows tpois rreg rts rug s sabl sample sapply
- scale scale.a scale.tau scan scatter.smooth screen screenplot
- se.contrast search segments semat seq set.seed show.settings sign
- signig sin sinh sink slice.index slm smooth.spline solve solve.qr
- solve.upper sort sort.list source spatial spec.ar spec.pgram spec.taper
- spectrum sphercov spin spline split split.screen splom sqrt SSI stars
- state.name statlib stdres stem step stepAIC stepfun stepwise stl stop
- Strauss stripplot structure studres subplot subset substutute substring
- sum summary summary.coxph summary.gam summary.lm supsmu surf.gls
- surf.ls Surv survdiff survexp survfit survreg svd sweep switch symbols
- synchronize sys.parent system t t.test table tan tanh tapply tempfile
- terms text text.default title tprint trace traceback tree tree.control
- trellis trellis.3d.args trellis.args trellis.device trellis.par.get
- trellis.par.set trmat tue.file.name trunc ts.intersect ts.lines ts.plot
- ts.points ts.union tspar ttest twoway unclass unique uniroot unix
- unix.time unlink unlist unpack update usa UseMethod usr var var.test
- varcomp variogram vcov.nlminb vcov.mlreg becnorm vi warning while
- wilcox.text win.colorscheme win.graph win.printer win3 window wireframe
- write write.table xor xyplot
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ S Arguments ◊◊◊◊ #
- #
-
- set SArguments {
- add aic all angle append as.is aux axes bandwidth best border box.ratio
- boxplots byrow center circles cohort col.names collapse conditional
- conf.int constant cor cuts data decay degree delta demean density depth
- detail detrend device df dframe differences dimmames.write dist drape
- eig else end entropy erase et evaluate exclude extrap factors family
- fence file fileout fill first frame frequency FUN full.precision fun
- gof.lag gradient h head header height help Hess hessian highlight hist
- horizontal in inches individual int inter.max intercept inverse
- inverted iter jacobian jitter k kernel labels lag lims link lineout
- local low lower lty lwd max max.subdiv maxit menu message method metric
- more multi.line n NA na.action na.last na.rm name ndeltat new nf ng
- niter noise normalize nu NULL nv offline onefile only.values orthogonal
- p parameters partial pattern pivot plane plotit pos prior prob
- probability probs psi.fun rang rectangles reverse rho rotation save
- scale scores se.fit sep short side sim simplify skip softmax span spar
- spin squares stars start subset summ symmetric taper test thermometers
- ticks tol trace trim tuning twodig type upper v var.axes what where
- which window wt x xl xlab xu y yl ylab yu
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ S Mass Library ◊◊◊◊ #
- #
-
- set SMassLibrary {
- Aids2 Boston Cars93 Choleski Cushings DDT GAGurine IQR Insurance
- Melanoma OME Pima.tr Rabbit Rubber Sitka Sitka89 Skye Traffic
- UScereal UScrime abbey accdeaths addterm animals anova.negbin area
- austres bcv beaver1 beaver2 biopsy biplot.princomp birthwt boxcox cats
- cement chem coop corresp cov.trob cpgram cpus crabs deaths digamma
- drivers dropterm eqscplot faithful farms fdeaths fgl forbes fractions
- galaxies gamma.dispersion gamma.shape.glm gehan genotype gilgais ginv
- glm.convert glm.nb hills histplot huber hubers immer isoMDS janka kde2d
- lda ldahist leuk lh loglm logtrans mammals mca mcycle mdeaths menarche
- michelson minn38 motors mvrnorm negative.binomial newcomb nottem npr1
- oats painters pairs.lda petrol phones plot.lda plot.mca predict.lda
- predict.mca predict.qda qda quine rational rlm rms.curv rnegbin road
- rock rotifer sammon ships shoes shrimp shuttle snails stdres steam
- stepAIC stormer studres summary.loglm summary.negbin summary.rlm survey
- synth.tr theta.md theta.mm topo trees trigamma truehist ucv vcov
- vcov.nlregb waders width.SJ write.matrix wtloss
- }
-
- # ===========================================================================
- #
- # Colorize S.
- #
- # Set all keyword lists, and colorize.
- #
- # Could also be called in a <mode>Prefs.tcl file
- #
-
- proc S::colorizeS {{pref ""}} {
-
- global SmodeVars SCommands SArguments SMassLibrary
- global SUserCommands SUserArguments Scmds SCommandList
-
- # First setting aside only the commands, for generic completions.
- set SCommandList [concat \
- $SCommands $SmodeVars(addCommands) $SUserCommands]
- if {$SmodeVars(useMassLibrary)} {
- append SCommandList " $SMassLibrary"
- }
- # Then, create the list of all keywords for completions.
- set Scmds [lsort [lunique [concat \
- $SCommandList $SArguments $SmodeVars(addArguments) $SUserArguments \
- ]]]
-
- # Commands
- regModeKeywords -a -k $SmodeVars(commandColor) S $SCommandList
-
- if {$SmodeVars(useMassLibrary)} {
- regModeKeywords -a -k $SmodeVars(commandColor) S $SMassLibrary
- } else {
- regModeKeywords -a -k {none} S $SMassLibrary
- }
- # Arguments
- set SArgumentColorList [concat \
- $SArguments $SmodeVars(addArguments) $SUserArguments]
- regModeKeywords -a -k $SmodeVars(argumentColor) S $SArgumentColorList
-
- # Symbols
- regModeKeywords -a \
- -m {$} \
- -k $SmodeVars(magicColor) S {} \
- -i "+" -i "-" -i "*" -i "_" -i "\\" \
- -I $SmodeVars(symbolColor)
-
- if {$pref != ""} {refresh}
- if {$pref == "useMassLibrary"} {S::rebuildMenu sMenu}
- }
-
- # Call this now.
-
- S::colorizeS
-
- # ===========================================================================
- #
- # Reload Completions.
- #
- # This is now an obsolete proc.
- #
-
- proc S::reloadCompletions {} {
- alertnote "\"S::reloadCompletions\" is an obsolete proc.\
- It should be removed from your SPrefs.tcl file."
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Key Bindings, Electrics ◊◊◊◊ #
- #
-
- # Known bug: Key-bindings from other global menus might conflict with those
- # defined in the Stata menu. This will help ensure that this doesn't happen.
-
- Bind 's' <cs> {S::switchToS ""} S
- Bind 'p' <cs> {S::processFile} S
- Bind 'p' <csz> {S::processSelection} S
- Bind 'p' <cs> {S::insertPath} S
-
- Bind 'n' <sz> {S::nextCommand} S
- Bind 'p' <sz> {S::prevCommand} S
- Bind 's' <sz> {S::selectCommand} S
- Bind 'c' <sz> {S::copyCommand} S
-
- Bind 'i' <cz> {S::reformatCommand} S
-
- Bind '\r' <s> {S::continueCommand} S
- Bind '\)' {S::electricRight "\)"} S
-
- # For those that would rather use arrow keys to navigate. Up and down
- # arrow keys will advance to next/prev command, right and left will also
- # set the cursor to the top of the window.
-
- Bind up <sz> {S::prevCommand 0 0} S
- Bind left <sz> {S::prevCommand 0 1} S
- Bind down <sz> {S::nextCommand 0 0} S
- Bind right <sz> {S::nextCommand 0 1} S
-
- # ===========================================================================
- #
- # S Carriage Return
- #
- # Inserts a carriage return, and indents properly.
- #
-
- proc S::carriageReturn {} {
-
- global SmodeVars
-
- if {[isSelection]} {deleteSelection}
-
- set pos1 [lineStart [getPos]]
- set pos2 [getPos]
- if {[regexp {^([\t ])*(\}|\)|dev\.off)} [getText $pos1 $pos2]]} {
- createTMark temp $pos2
- catch {bind::IndentLine}
- gotoTMark temp ; removeTMark temp
- }
- insertText "\r"
- catch {bind::IndentLine}
- }
-
- # ===========================================================================
- #
- # Electric Left, Right
- #
- # Adapted from "tclMode.tcl"
- #
-
- proc S::electricLeft {} {
-
- if {[literalChar]} {
- typeText "\{"
- return
- }
- set pat "\}\[ \t\r\n\]*(else(if)?)\[ \t\r\n\]*\$"
- set pos [getPos]
- if { [set result [findPatJustBefore "\}" $pat $pos word]] == "" } {
- insertText "\{"
- return
- }
- # we have an if/else(if)/else
- switch -- $word {
- "else" {
- deleteText [lindex $result 0] $pos
- elec::Insertion "\} $word \{\r\t••\r\}\r••"
- }
- "elseif" {
- deleteText [lindex $result 0] $pos
- elec::Insertion "\} $word \{••\} \{\r\t••\r\}\r••"
- }
- }
- }
-
- proc S::electricRight {{char "\}"}} {
-
- if {[literalChar]} {
- typeText $char
- return
- }
- set pos [getPos]
- typeText $char
- if {![regexp {[^ \t]} [getText [lineStart $pos] $pos]]} {
- set pos [lineStart $pos]
- createTMark temp [getPos]
- catch {bind::IndentLine}
- gotoTMark temp ; removeTMark temp
- bind::CarriageReturn
- }
- if {[catch {blink [matchIt $char [pos::math $pos - 1]]}]} {
- beep ; message "No matching $char !!"
- }
- }
-
- # ===========================================================================
- #
- # Continue Command
- #
- # Over-rides the automatic indentation of lines that begin with \} or \)
- # so that additional text can be entered.
- #
-
- proc S::continueCommand {} {
-
- global indent_amounts
-
- bind::CarriageReturn
- if {[pos::compare [getPos] != [maxPos]]} {
- set nextChar [getText [getPos] [pos::math [getPos] + 1]]
- if {$nextChar == "\}" || $nextChar == "\)"} {
- insertText [text::indentOf $indent_amounts(2)]
- }
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Indentation ◊◊◊◊ #
- #
- # S::correctIndentation is necessary for Smart Paste, and returns the
- # correct level of indentation for the current line. S::indentLine uses
- # this level to indent the current line.
- #
- # In S::correctIndentation, we grab the previous non-commented line, remove
- # all of the characters besides braces, quotes, and hashmarks, and then
- # convert it all to a list to be evaluated. Braces and hashmarks contained
- # within quotes, as well as literal characters, should all be ignored and
- # the remaining braces are used to determine the correct level of nesting.
- #
-
- proc S::indentLine {{pos ""}} {
-
- if {$pos == ""} {set pos [getPos]}
- # Get details of current line.
- set posBeg [lineStart [getPos]]
- set text [getText $posBeg [nextLineStart $posBeg]]
- regexp {^[ \t]*} $text white
- set posNext1 [pos::math $posBeg + [string length $white]]
- set posNext2 [pos::math $posNext1 + 1]
- if {[pos::compare $posNext2 > [maxPos]]} {
- set posNext2 [maxPos]
- }
- # Determine the correct level of indentation for this line, given the
- # next character.
- set lwhite [S::correctIndentation $pos [getText $posNext1 $posNext2]]
- set lwhite [text::indentOf $lwhite]
- if {$white != $lwhite} {
- replaceText $posBeg $posNext1 $lwhite
- }
- goto [pos::math $posBeg + [string length $lwhite]]
- }
-
- proc S::correctIndentation {pos {next ""}} {
-
- global indent_amounts SmodeVars
-
- set posBeg [lineStart $pos]
- # Get information about this line, previous line ...
- set thisLine [S::getCommandLine $posBeg 1 1]
- set prevLine1 [S::getCommandLine [pos::math $posBeg - 1] 0 1]
- set prevLine2 [S::getCommandLine [pos::math [lindex $prevLine1 0] - 1] 0 1]
- set lwhite [lindex $prevLine1 1]
- # If we have a previous line ...
- if {[pos::compare [lindex $prevLine1 0] != $posBeg]} {
- # Indent if the preceding command was a postscript command.
- set pL1 [string trim [lindex $prevLine1 2]]
- if {[regexp {^[\t ]*postscript([\t ]*\()} $pL1]} {
- incr lwhite $indent_amounts(2)
- }
- # Indent if the last line did not terminate the command.
- if {[string trimright $pL1 "\\"] != $pL1} {
- incr lwhite $indent_amounts(1)
- }
- # Check to make sure that the previous command was not itself a
- # continuation of the line before it.
- if {[pos::compare [lindex $prevLine2 0] != [lindex $prevLine1 0]]} {
- set pL2 [string trim [lindex $prevLine2 2]]
- if {[string trimright $pL2 "\\"] != $pL2} {
- incr lwhite $indent_amounts(-1)
- }
- }
- # Find out if there are any unbalanced {,},(,) in the last line.
- regsub -all {[^ \{\}\(\)\"\#\\]} $pL1 { } line
- # Remove all literals.
- regsub -all {\\\{|\\\}|\\\(|\\\)|\\\"|\\\#} $line { } line
- regsub -all {\\} $line { } line
- # Remove everything surrounded by quotes.
- regsub -all {\"([^\"]+)\"} $line { } line
- regsub -all {\"} $line { } line
- # Remove all characters following the first valid comment.
- if {[regexp {\#} $line]} {
- set line [string range $line 0 [string first {#} $line]]
- }
- # Now turn all braces into 2's and -2's
- regsub -all {\{|\(} $line { 2 } line
- regsub -all {\}|\)} $line { -2 } line
- # This list should now only contain 2's and -2's.
- foreach i $line {
- if {$i == "2" || $i == "-2"} {incr lwhite $indent_amounts($i)}
- }
- # Did the last line start with a lone \) or \} ? If so, we want to
- # keep the indent, and not make call it an unbalanced line.
- if {[regexp {^[\t ]*(\}|\))} $pL1]} {
- incr lwhite $indent_amounts(2)
- }
- }
- # If we have a current line ...
- if {[pos::compare [lindex $thisLine 0] == $posBeg]} {
- # Reduce the indent if the first non-whitespace character of this
- # line is ) or \}.
- set tL [lindex $thisLine 2]
- if {$next == "\}" || $next == ")" || [regexp {^[\t ]*(\}|\)|dev\.off)} $tL]} {
- incr lwhite $indent_amounts(-2)
- }
- }
- # Now we return the level to the calling proc.
- return [expr {$lwhite > 0 ? $lwhite : 0}]
- }
-
- # ===========================================================================
- #
- # Get Command Line
- #
- # Find the next/prev command line relative to a given position, and return
- # the position in which it starts, its indentation, and the complete text
- # of the command line. If the search for the next/prev command fails,
- # return an indentation level of 0.
- #
-
- proc S::getCommandLine {pos {direction 1} {ignoreComments 1}} {
-
- if {$ignoreComments} {
- set pat {^[\t ]*[^\t\r\n\# ]}
- } else {
- set pat {^[\t ]*[^\t\r\n ]}
- }
- set posBeg [pos::math [lineStart $pos] - 1]
- if {[pos::compare $posBeg < [minPos]]} {
- set posBeg [minPos]
- }
- set lwhite 0
- if {![catch {search -f $direction -r 1 $pat $pos} match]} {
- set posBeg [lindex $match 0]
- set lwhite [posX [pos::math [lindex $match 1] - 1]]
- }
- set posEnd [pos::math [nextLineStart $posBeg] - 1]
- if {[pos::compare $posEnd > [maxPos]]} {
- set posEnd [maxPos]
- }
- return [list $posBeg $lwhite [getText $posBeg $posEnd]]
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Command Double Click ◊◊◊◊ #
- #
- # Checks to see if the highlighted word appears in any keyword list, and if
- # so, sends the selected word to the www.mathsoft.com help site.
- #
- # (The above is not yet implemented -- where's a S help site ???)
- #
- # Control-Command double click will insert syntax information in status bar.
- # Shift-Command double click will insert commented syntax information in window.
- #
- # (The above is not yet implemented -- need to enter all of the syntax info.)
- #
-
- proc S::DblClick {from to shift option control} {
-
- # First make sure that Scmds has been defined.
-
- SCompletions.tcl
-
- global SmodeVars Scmds SSyntaxMessage
-
- set where [getPos]
-
- select $from $to
- set command [getSelect]
-
- set varDef "$command+\[\t \]+(<\-|_)"
-
- if {![catch {search -s -f 1 -r 1 -m 0 $varDef [minPos]} match]} {
- # First check current file for a variable (etc) definition, and if
- # found ...
- placeBookmark
- goto [lineStart [lindex $match 0]]
- message "press <Ctl .> to return to original cursor position"
- return
- # Could next check any open windows, or files in the current
- # window's folder ... but not implemented. For now, variables
- # (etc) need to be defined in current file.
- } elseif {[lsearch -exact $Scmds $command] == -1} {
- message "\"$command\" is not defined as an S system keyword."
- return
- }
- # Defined as a keyword, determine if there's a syntax message.
- # Any modifiers pressed?
- if {$control} {
- # CONTROL -- Just put syntax message in status bar window
- if {[info exists SSyntaxMessage($command)]} {
- message "$SSyntaxMessage($command)"
- } else {
- message "Sorry, no syntax information available for $command"
- }
- } elseif {$shift} {
- # SHIFT --Just insert syntax message as commented text
- if {[info exists SSyntaxMessage($command)]} {
- endOfLine
- insertText "\r"
- insertText "$SSyntaxMessage($command)"
- comment::Line
- } else {
- message "Sorry, no syntax information available for $command"
- }
- } elseif {$option && !$SmodeVars(localHelp)} {
- # Now we have four possibilities, based on "option" key and the
- # preference for "local Help".
- #
- # OPTION, local help isn't checked -- Send command to local application
- S::localCommandHelp $command
- } elseif {$option && $SmodeVars(localHelp)} {
- # OPTION, but local help is checked -- Send command for on-line help.
- S::wwwCommandHelp $command
- } elseif {$SmodeVars(localHelp)} {
- # No modifiers, local help is checked -- Send command to local app.
- S::localCommandHelp $command
- } else {
- # No modifiers, no local help checked -- Send command for on-line
- # help. This is the "default" behavior.
- S::wwwCommandHelp $command
- }
- }
-
- # ===========================================================================
- #
- # WWW Command Help
- #
- # Send command to defined url, prompting for text if necessary.
- #
-
- proc S::wwwCommandHelp {{command ""}} {
-
- global SmodeVars
-
- if {$command == ""} {
- set command [prompt "on-line S+/R help for ... " [getSelect]]
- # set command [statusPrompt "on-line help for ... " ]
- }
- message "\"$command\" sent to $SmodeVars(helpUrl)"
- icURL $SmodeVars(helpUrl)${command}.html
- }
-
- # ===========================================================================
- #
- # Local Command Help
- #
- # Find a local help file, and open it in a browser.
- # Prompt for text if necessary.
- #
- # We're assuming that the help does exist as a file somewhere, as opposed
- # to being an internal application help function. At the moment, we also
- # assume that this file is html, although that could be a mode option as
- # well.
- #
- # This needs more work ...
- #
-
- proc S::localCommandHelp {{command ""}} {
-
- global SmodeVars
-
- set app $SmodeVars(application)
-
- if {$command == ""} {
- set command [prompt "local $app application help for ... " [getSelect]]
- # set command [statusPrompt "local S application help for ... " ]
- }
- S::processSelection "help ($command)" "$app"
- }
-
- # proc S::localCommandHelp {{command ""} {app ""}} {
- #
- # global SmodeVars tcl_platform
- #
- # if {$app == ""} {
- # set app $SmodeVars(application)
- # }
- # if {$command == ""} {
- # set command [prompt "local $app application help for ... " [getSelect]]
- # # set command [statusPrompt "local S-Plus application help for ..." ]
- # }
- # set pf $tcl_platform(platform)
- #
- # # We have six possible options here, based on platform and application.
- # # For each option, we want to create the path to the help file.
- #
- # if {$pf == "macintosh"} {
- # # We'll kill this right now. The rest is for future code ...
- # S::betaMessage
- # # Make sure that the Macintosh application for the signature exists.
- # if {[catch {[nameFromAppl [S::sig $app]]}]} {
- # S::setApplication $app
- # }
- # if {$SmodeVars(application) == "R"} {
- # # Macintosh, R
- # } else {
- # # Macintosh, S+
- # }
- # } elseif {$pf == "windows" || $pf == "unix"} {
- # # Make sure that the Windows application for the signature exists.
- # # We assume that this will work for unix, too.
- # if {![file exists [S::sig $app]]} {
- # S::setApplication $app
- # }
- # if {$SmodeVars(application) == "R"} {
- # # Windows, R
- # set appRoot [file dirname [file dirname [S::sig]]]
- # set helpLib [file join $appRoot library base html]
- # set helpFile [file join $helpLib ${command}.html]
- # } else {
- # # Windows, S+
- # S::betaMessage
- # }
- # }
- # # Now we look for the actual help file.
- # if {![file exists $helpFile]} {
- # beep ; message "Sorry, no help file for \"$command\" was found."
- # error "No help file found for \"$command\"."
- # } else {
- # help::openFile $helpFile
- # }
- # }
-
-
- # ===========================================================================
- #
- # ◊◊◊◊ Mark File and Parse Functions ◊◊◊◊ #
- #
-
- # ===========================================================================
- #
- # S Mark File
- #
- # This will return the first 35 characters from the first non-commented
- # word that appears in column 0. All other output files (those not
- # recognized) will take into account the additional left margin elements
- # added by S+/R.
- #
-
- proc S::MarkFile {{type ""}} {
-
- removeAllMarks
-
- message "Marking File …"
-
- set pos [minPos]
- set count 0
- # Figure out what type of file this is -- source, or output.
- # The variable "type" refers to a call from the S menu.
- # Otherwise we try to figure out the type based on the file's suffix.
- if {$type == ""} {
- if {[win::CurrentTail] == "* S Mode Example *"} {
- # Special case for Mode Examples, but only if called from
- # Marks menu. (Called from S menu, "type" will over-ride.)
- set type ".s"
- } else {
- set type [file extension [win::CurrentTail]]
- }
- }
- # Now set the mark regexp.
- if {$type == ".s" } {
- # Source file.
- set markExpr {^(###[ ]|####[ ])?[-a-zA-Z0-9]}
- } else {
- # None of the above, so assume that it's output
- set markExpr {^(> )+(###[ ]|####[ ])?[-a-zA-Z0-9]}
- }
- # Mark the file
- while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $markExpr $pos} match]} {
- incr count
- set posBeg [lindex $match 0]
- set posEnd [nextLineStart $posBeg]
- if {[pos::compare $posEnd > [maxPos]]} {set posEnd [maxPos]}
- set line [string trimright [getText $posBeg $posEnd]]
- # Get rid of the leading "> " for output files.
- regsub {^ >} $line {} line
- # Get rid of braces.
- regsub -all {\{|\[} $line {(} line
- regsub -all {\}|\]} $line {)} line
- set line " $line"
- if {[regsub { #### } $line {* } line]} {
- incr count -1
- } elseif {[regsub { ### } $line {• } line]} {
- incr count -1
- }
- if {[string length $line] > 35} {
- set line "[string range $line 0 35] ..."
- }
- setNamedMark $line $posBeg $posBeg $posBeg
- set pos $posEnd
- }
- message "This file contains $count commands."
- }
-
- # ===========================================================================
- #
- # S Parse Functions
- #
- # Borrowed from C++, with modifications.
- #
-
- proc S::parseFuncs {} {
-
- global sortFuncsMenu
-
- set funcExpr {[A-Za-z0-9~_.]+[A-Za-z0-9~_.]+[\t ]*\(}
- set parseExpr {\b([-\w_:.]+)[\t ]*\(}
-
- set pos [minPos]
- set m {}
- while {[set result [search -s -f 1 -r 1 -i 0 -n $funcExpr $pos]] != ""} {
- set pos1 [lindex $result 0]
- set pos2 [lindex $result 1]
- regexp -- $parseExpr [getText $pos1 $pos2] match command
- # Get the line that contains this command.
- set commandLine [getText [lineStart $pos1] $pos2]
- # Strip off anything after the first valid comment.
- regsub -all {\\\#} $commandLine { } commandLine
- if {[regexp {\#} $commandLine]} {
- set firstComment [string first {#} $commandLine]
- set commandLine [string range $commandLine 0 $firstComment]
- }
- if {[regexp $command $commandLine]} {
- # The command is still in the line.
- lappend m [list $command $pos1]
- }
- set pos [nextLineStart $pos2]
- }
- if {$sortFuncsMenu} {
- regsub -all "\[\{\}\]" [lsort -ignore $m] "" m
- } else {
- regsub -all "\[\{\}\]" $m "" m
- }
- return $m
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ -------------------- ◊◊◊◊ #
- #
- # ◊◊◊◊ S Menu ◊◊◊◊ #
- #
- # based upon the Stata menu, contributed by
- # L. Phillip Schumm <pschumm@uchicago.edu>
- #
-
- proc sMenu {} {}
-
- # Tell Alpha what procedures to use to build all menus, submenus.
-
- menu::buildProc sMenu S::buildMenu
- menu::buildProc s+Help S::buildHelpMenu
- menu::buildProc rHelp S::buildHelpMenu
- menu::buildProc sModeKeywords S::buildKeywordsMenu
- menu::buildProc markSFileAs… S::buildMarkMenu
-
- # First build the main S+ menu.
-
- proc S::buildMenu {} {
-
- global sMenu SmodeVars
-
- set app $SmodeVars(application)
- set lowApp [string tolower $SmodeVars(application)]
-
- set menuList [list \
- "${lowApp}HomePage" \
- "/S<U<OswitchTo${app}" \
- [list Menu -n ${lowApp}Help -M S {}] \
- "(-" \
- [list Menu -n sModeKeywords -M S {}] \
- [list Menu -n markSFileAs… -M S {}] \
- "(-" \
- "/P<U<OprocessFile" \
- "/P<U<O<BprocessSelection" \
- "(-" \
- "/I<U<OinsertPath" \
- "/b<UcontinueCommand" \
- "(-" \
- "/N<U<BnextCommand" \
- "/P<U<BprevCommand" \
- "/S<U<BselectCommand" \
- "/I<B<OreformatCommand" \
- ]
- set submenus [list ${lowApp}Help sModeKeywords markSFileAs… ]
- return [list build $menuList S::menuProc $submenus $sMenu]
- }
-
- # Then build the "S+ Help" submenu.
-
- proc S::buildHelpMenu {} {
-
- global SmodeVars SPrefsInMenu alpha::platform
-
- # Determine which key should be used for "Help", with F8 as option.
-
- if {!$SmodeVars(noHelpKey)} {
- set key "/t"
- } else {
- set key "/l"
- }
-
- # Reverse the local, www key bindings depending on the value of the
- # 'Local Help" variable.
-
- if {$SmodeVars(localHelp) == 0} {
- set menuList [list \
- "${key}<OwwwCommandHelp…" \
- "${key}<IlocalCommandHelp…" \
- ]
- } else {
- set menuList [list \
- "${key}<OlocalCommandHelp…" \
- "${key}<IwwwCommandHelp…" \
- ]
- }
- lappend menuList "(-"
- if {$SmodeVars(application) == "S+"} {
- lappend menuList "r"
- lappend menuList "!•s+"
- } else {
- lappend menuList "!•r"
- lappend menuList "s+"
- }
- lappend menuList "(-"
- if {${alpha::platform} == "alpha"} {
- set prefix "!√"
- } else {
- set prefix "!•"
- }
- foreach pref $SPrefsInMenu {
- if {$SmodeVars($pref)} {
- lappend menuList "${prefix}$pref"
- } else {
- lappend menuList "$pref"
- }
- }
- lappend menuList "(-"
- lappend menuList "setRApplication"
- lappend menuList "setS+Application"
- lappend menuList "(-"
- lappend menuList "${key}<BsModeHelp"
-
- return [list build $menuList S::helpProc {}]
- }
-
- # Then build the "S Mode Keywords" submenu.
-
- proc S::buildKeywordsMenu {} {
-
- set menuList [list \
- "listKeywords" \
- "checkKeywords" \
- "addNewCommands" \
- "addNewArguments" \
- ]
- return [list build $menuList S::keywordsProc {}]
- }
-
- # Then build the "Mark S File As" submenu.
-
- proc S::buildMarkMenu {} {
-
- global SmodeVars alpha::platform
-
- set menuList [list \
- "source" \
- "output" \
- "(-" \
- ]
- if {${alpha::platform} == "alpha"} {
- set prefix "!√"
- } else {
- set prefix "!•"
- }
- if {$SmodeVars(autoMark)} {
- lappend menuList "${prefix}autoMark"
- } else {
- lappend menuList "autoMark"
- }
- return [list build $menuList S::markFileProc {}]
- }
-
- proc S::rebuildMenu {{menuName "sMenu"} {pref ""}} {
- menu::buildSome $menuName
- }
-
- # Dim some menu items when there are no open windows.
- set menuItems {
- processFile processSelection markSFileAs…
- insertPath
- nextCommand prevCommand selectCommand
- }
- foreach i $menuItems {
- hook::register requireOpenWindowsHook [list sMenu $i] 1
- }
- unset i menuItems
-
- # Now we actually build the S+ menu.
-
- menu::buildSome sMenu
-
- # ===========================================================================
- #
- # ◊◊◊◊ S-Plus menu support ◊◊◊◊ #
- #
-
- # This is the procedure called for all main menu items.
-
- proc S::menuProc {menu item} {S::$item}
-
- # Give a beta message for untested features / menu items.
-
- proc S::betaMessage {{kill 1}} {
-
- beep ; message "Sorry, this feature has not been fully implemented."
- if {$kill} {return -code return}
- }
-
- # ===========================================================================
- #
- # Open the S / R+ home page.
- #
-
- proc S::s+HomePage {{app "S+"}} {
-
- global SmodeVars
-
- if {$app == ""} {set app $SmodeVars(application)}
- set lowApp [string tolower $app]
-
- url::execute $SmodeVars(${lowApp}HomePage)
- }
-
- proc S::rHomePage {} {S::s+HomePage "R"}
-
- # ===========================================================================
- #
- # Switch to S-Plus or R application
- #
-
- proc S::switchToS+ {{app "S+"}} {
-
- global SmodeVars
-
- if {$app == ""} {set app $SmodeVars(application)}
-
- app::launchFore '[S::sig $app]'
- }
-
- proc S::switchToR {} {S::switchToS+ "R"}
-
-
- # ===========================================================================
- #
- # Return the S+ / R signature.
- #
-
- proc S::sig {{app "S+"}} {
-
- global SmodeVars tcl_platform
-
- if {$app == ""} {set app $SmodeVars(application)}
-
- set lowApp [string tolower $app]
- set capApp [string toupper $app]
- set pf $tcl_platform(platform)
-
- if {$pf == "macintosh"} {
- # Make sure that the Macintosh application for the signature exists.
- if {[catch {nameFromAppl $SmodeVars(${lowApp}Sig)}]} {
- alertnote "Looking for the $capApp application ..."
- S::setApplication $lowApp
- }
- } elseif {$pf == "windows" || $pf == "unix"} {
- # Make sure that the Windows application for the signature exists.
- # We assume that this will work for unix, too.
- if {![file exists $SmodeVars(${lowApp}Sig)]} {
- alertnote "Looking for the $capApp application ..."
- S::setApplication $lowApp
- }
- }
- return $SmodeVars(${lowApp}Sig)
- }
-
- # ===========================================================================
- #
- # Set Application
- #
- # Prompt the user to locate the local S application.
- #
-
- proc S::setApplication {{app ""}} {
-
- global mode SmodeVars
-
- if {$app == ""} {set app $SmodeVars(application)}
-
- set lowApp [string tolower $app]
- set capApp [string toupper $app]
-
- set newSig ""
- set newSig [dialog::askFindApp $capApp $SmodeVars(${lowApp}Sig)]
-
- if {$newSig != ""} {
- set SmodeVars(${lowApp}Sig) "$newSig"
- set oldMode $mode
- set mode "S"
- synchroniseModeVar "${lowApp}Sig" $SmodeVars(${lowApp}Sig)
- set mode $oldMode
- message "The $capApp signature has been changed to \"$newSig\"."
- } else {
- message "Cancelled."
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Help ◊◊◊◊ #
- #
-
- proc S::helpProc {menu item} {
-
- global SmodeVars SPrefsInMenu
-
- if {$item == "wwwCommandHelp"} {
- S::wwwCommandHelp
- } elseif {$item == "localCommandHelp"} {
- S::localCommandHelp
- } elseif {$item == "r" || $item == "s+"} {
- S::selectApplication $item
- S::rebuildMenu
- } elseif {[lsearch -exact $SPrefsInMenu $item] != -1} {
- S::flagFlip $item
- S::rebuildMenu
- } elseif {$item == "setRApplication"} {
- S::setApplication "r"
- } elseif {$item == "setS+Application"} {
- S::setApplication "s+"
- } elseif {$item == "sModeHelp"} {
- package::helpFile "S"
- } else {
- S::$item
- }
- }
-
- # Choose between R and S+
-
- proc S::selectApplication {app} {
-
- global mode SmodeVars
-
- set app [string toupper $app]
-
- set SmodeVars(application) $app
- set oldMode $mode
- set mode "S"
- synchroniseModeVar application $SmodeVars(application)
- set mode $oldMode
- message "Default application is now $app."
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Keywords ◊◊◊◊ #
- #
-
- proc S::keywordsProc {menuName item} {
-
- global Scmds
-
- if {$item == "listKeywords"} {
- set keywords [listpick -l -p "Current S mode keywords…" $Scmds]
- foreach keyword $keywords {
- S::checkKeywords $keyword
- }
- } elseif {$item == "addNewCommands" || $item == "addNewArguments"} {
- set item [string trimleft $item "addNew"]
- if {$item == "Commands" && [llength [winNames]] && [askyesno \
- "Would you like to add all of the \"extra\" commands from this window\
- to the \"Add Commands\" preference?"] == "yes"} {
- S::addWindowCommands
- } else {
- S::addKeywords $item
- }
- } else {
- S::$item
- }
- }
-
- # ===========================================================================
- #
- # S::addWindowCommands
- #
- # Add all of the "extra" commands which appear in entries in this window.
- #
-
- proc S::addWindowCommands {} {
-
- global mode Scmds SmodeVars
-
- if {![llength [winNames]]} {
- message "Cancelled -- no current window!"
- return
- }
-
- message "Scanning [win::CurrentTail] for all commands…"
-
- set pos [minPos]
- set pat1 {[A-Za-z0-9~_.]+[A-Za-z0-9~_.]+[\t ]*\(}
- set pat2 {\b([-\w_:.]+)\s*\(}
- while {![catch {search -f 1 -r 1 $pat1 $pos} match]} {
- set pos [nextLineStart [lindex $match 1]]
- set pos1 [lindex $match 0]
- set pos2 [lindex $match 1]
- regexp -- $pat2 [getText $pos1 $pos2] match aCommand
- # Get the line that contains this command.
- set commandLine [getText [lineStart $pos1] $pos2]
- # Strip off anything after the first valid comment.
- regsub -all {\\\#} $commandLine { } commandLine
- if {[regexp {\#} $commandLine]} {
- set firstComment [string first {#} $commandLine]
- set commandLine [string range $commandLine 0 $firstComment]
- }
- if {[regexp $aCommand $commandLine] && ![lcontains Scmds $aCommand]} {
- # The command is still in the line, and not recognized.
- append SmodeVars(addCommands) " $aCommand"
- }
- }
- set SmodeVars(addCommands) [lsort [lunique $SmodeVars(addCommands)]]
- set oldMode $mode
- set mode "S"
- synchroniseModeVar addCommands $SmodeVars(addCommands)
- set mode $oldMode
- if {[llength $SmodeVars(addCommands)]} {
- S::colorizeS
- listpick -p "The \"Add Commands\" preference includes:" \
- $SmodeVars(addCommands)
- message "Use the \"Mode Prefs --> Preferences\" menu item to edit keyword lists."
- } else {
- message "No \"extra\" commands from this window were found."
- }
- }
-
- # ===========================================================================
- #
- # S::addKeywords
- #
- # Prompt the user to add keywords for a given category.
- #
-
- # Query existing lists of keywords, and add to the mode preferences.
-
- proc S::addKeywords {category {keywords ""}} {
-
- global mode SmodeVars
-
- if {$keywords == ""} {
- set keywords [prompt "Enter new $SmodeVars(application) $category:" ""]
- }
-
- # Check to see if the keyword is already defined.
- foreach keyword $keywords {
- set checkStatus [S::checkKeywords $keyword 1 0]
- if {$checkStatus != 0} {
- alertnote "Sorry, \"$keyword\" is already defined\
- in the $checkStatus list."
- message "Cancelled."
- return -code return
- }
- }
- # Keywords are all new, so add them to the appropriate mode preference.
- append SmodeVars(add$category) " $keywords"
- set SmodeVars(add$category) [lsort $SmodeVars(add$category)]
- set oldMode $mode
- set mode "S"
- synchroniseModeVar add$category $SmodeVars(add$category)
- set mode $oldMode
- S::colorizeS
- message "\"$keywords\" added to $category preference."
- }
-
- proc S::checkKeywords {{newKeywordList ""} {quietly 0} {noPrefs 0}} {
-
- global SmodeVars
-
- global SCommands SUserCommands SArguments SUserArguments SMassLibrary
-
- set type 0
- if {$newKeywordList == ""} {
- set quietly 0
- set newKeywordList [prompt "Enter S mode keywords to be checked:" ""]
- }
- # Check to see if the new keyword(s) is already defined.
- foreach newKeyword $newKeywordList {
- if {[lsearch -exact $SCommands $newKeyword] != "-1"} {
- set type SCommands
- } elseif {[lsearch -exact $SUserCommands $newKeyword] != "-1"} {
- set type SUserCommands
- } elseif {[lsearch -exact $SArguments $newKeyword] != "-1"} {
- set type SArguments
- } elseif {[lsearch -exact $SUserArguments $newKeyword] != "-1"} {
- set type SUserArguments
- } elseif {[lsearch -exact $SMassLibrary $newKeyword] != "-1"} {
- set type SMassLibrary
- } elseif {!$noPrefs && \
- [lsearch -exact $SmodeVars(addCommands) $newKeyword] != "-1"} {
- set type SmodeVars(addCommands)
- } elseif {!$noPrefs && \
- [lsearch -exact $SmodeVars(addArguments) $newKeyword] != "-1"} {
- set type SmodeVars(addArguments)
- }
- if {$quietly} {
- # When this is called from other code, it should only contain
- # one keyword to be checked, and we'll return it's type.
- return "$type"
- } elseif {!$quietly && $type == 0} {
- alertnote "\"$newKeyword\" is not currently defined\
- as a S mode keyword"
- } elseif {$type != 0} {
- # This will work for any other value for "quietly", such as 2
- alertnote "\"$newKeyword\" is currently defined as a keyword\
- in the \"$type\" list."
- }
- set type 0
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Processing ◊◊◊◊ #
- #
-
- # ===========================================================================
- #
- # Process File
- #
- # Send entire file to S+ / R for processing, adding carriage return at end
- # of file if necessary.
- #
- # Optional "f" argument allows this to be called by other code, or to be
- # sent via a Tcl shell window.
- #
-
- proc S::processFile {{f ""} {app ""}} {
-
- global SmodeVars
-
- if {$f != ""} {file::openAny $f}
- set f [win::Current]
-
- if {$app == ""} {set app $SmodeVars(application)}
-
- set lowApp [string tolower $app]
- set capApp [string toupper $app]
-
- set dirtyWindow [winDirty]
- set dontSave 0
- if {$dirtyWindow && [askyesno \
- "Do you want to save the file before sending it to $capApp?"] == "yes"} {
- save
- } else {
- set dontSave 1
- }
- if {!$dontSave && [lookAt [pos::math [maxPos] - 1]] != "\r"} {
- set pos [getPos]
- goto [maxPos]
- insertText "\r"
- goto $pos
- alertnote "Carriage return added to end of file."
- save
- }
-
- app::launchBack '[S::sig $capApp]'
- sendOpenEvent noReply '[S::sig $capApp]' $f
- switchTo '[S::sig $capApp]'
- }
-
- # ===========================================================================
- #
- # Process Selection
- #
- # Procedure to implement transfer of selected lines to S+ / R for processing.
- #
-
- proc S::processSelection {{selection ""} {app ""}} {
-
- global PREFS SmodeVars
-
- if {$app == ""} {set app $SmodeVars(application)}
-
- set lowApp [string tolower $app]
- set capApp [string toupper $app]
-
- if {$selection == ""} {
- if {![isSelection]} {
- message "No selection -- cancelled."
- return
- } else {
- set selection [getSelect]
- }
- }
- file::ensureDirExists [file join $PREFS S-tmp]
- set newFile [file join $PREFS S-tmp temp-S.s]
- file::writeAll $newFile $selection 1
-
- app::launchBack '[S::sig $capApp]'
- sendOpenEvent noReply '[S::sig $capApp]' $newFile
- switchTo '[S::sig $capApp]'
- }
-
- proc S::quitHook {} {temp::cleanup S-tmp}
-
- # ===========================================================================
- #
- # ◊◊◊◊ Marks ◊◊◊◊ #
- #
-
- proc S::markFileProc {menu item} {
-
- if {$item == "source"} {
- S::MarkFile {.s}
- } elseif {$item == "output"} {
- # doesn't really matter what we put for the mark file "type" here,
- # since output is the default if other "if ..." cases aren't met.
- S::MarkFile {.out}
- } elseif {$item == "autoMark"} {
- S::flagFlip autoMark
- S::rebuildMenu markS+FileAs…
- S::rebuildMenu markRFileAs…
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Insertions ◊◊◊◊ #
- #
-
- proc S::insertPath {} {
-
- global file::separator
-
- set path ""
- set t ""
- append t "\"${file::separator}"
- set path [getfile "Choose path of target file:"]
- if {$path != ""} {
- append t $path
- append t "\""
- insertText $t
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Navigation ◊◊◊◊ #
- #
-
- # Next/Prev command can simply return the position of the next command
- # (quietly == 1), move the cursor to the next command (placing the cursor
- # at the top of the window if toTop == 1), extend the current selection to
- # the end of the this command, or (if the current command is already
- # highlighted in its entirety) extend the current selection to the end of
- # the next command.
- #
-
- proc S::nextCommand {{quietly 0} {toTop 0}} {
-
- if {[pos::compare [selEnd] == [maxPos]]} {
- set pos [maxPos]
- } else {
- set pos [pos::math [selEnd] + 1]
- }
- set pat {^[^\r\n\t \#\}\)]}
- if {![catch {search -f 1 -r 1 $pat $pos} match]} {
- set pos [lineStart [lindex $match 1]]
- } else {
- set pos [maxPos]
- }
- if {$quietly} {
- return $pos
- } elseif {[isSelection]} {
- set limit1 [lindex [S::getCommand [selEnd]] 1]
- set limit2 [lindex [S::getCommand $pos ] 1]
- if {$limit2 == "-1"} {set limit2 [maxPos]}
- if {$limit1 == "-1"} {set limit1 $limit2}
- if {[pos::compare [selEnd] < $limit1]} {
- select [getPos] $limit1
- } else {
- select [getPos] $limit2
- }
- } elseif {$pos == [maxPos]} {
- message "No further commands in the file."
- return
- } else {
- goto $pos
- message [getText $pos [nextLineStart $pos]]
- }
- if {$toTop} {insertToTop}
- }
-
- proc S::prevCommand {{quietly 0} {toTop 0}} {
-
- if {[pos::compare [getPos] == [minPos]]} {
- set pos [minPos]
- } else {
- set pos [pos::math [getPos] - 1]
- }
- set pat {^[^\r\n\t \#\}\)]}
- if {![catch {search -f 0 -r 1 $pat $pos} match]} {
- set pos [lineStart [lindex $match 0]]
- } else {
- set pos [minPos]
- }
- if {$quietly} {
- return $pos
- } elseif {[isSelection]} {
- # Going backwards is actually easier with selections.
- select $pos [selEnd]
- } elseif {$pos == [minPos]} {
- message "No further commands in the file."
- return
- } else {
- goto $pos
- message [getText $pos [nextLineStart $pos]]
- }
- if {$toTop} {insertToTop}
- return $pos
- }
-
- proc S::searchFunc {direction} {
-
- if {$direction} {
- S::nextCommand
- } else {
- S::prevCommand
- }
- }
-
- proc S::selectCommand {} {
-
- set pos [getPos]
- set limits [S::getCommand $pos]
- set posBeg [lindex $limits 0]
- set posEnd [lindex $limits 1]
-
- if {$posBeg != "-1" && $posEnd != "-1" && \
- [pos::compare $pos >= $posBeg] && [pos::compare $pos <= $posEnd]} {
- select $posBeg $posEnd
- } else {
- message "The cursor is not within a command."
- error "The cursor is not within a command."
- }
- }
-
- proc S::copyCommand {{quietly 0}} {
-
- set pos [getPos]
- if {[set posBeg [lindex [S::getCommand $pos] 0]] != "-1"} {
- goto $posBeg
- forwardWord
- set posEnd [getPos]
- if {!$quietly} {
- select $posBeg $posEnd
- copy
- message "\"[getText $posBeg $posEnd]\" copied to clipboard."
- }
- goto $pos
- return [getText $posBeg $posEnd]
- } elseif {!$quietly} {
- message "The cursor is not within a command."
- }
- return ""
- }
-
- proc S::reformatCommand {} {
-
- if {![isSelection]} {S::selectCommand}
- message "Reformatting …"
- ::indentRegion
- goto [pos::math [getPos] -1]
- goto [S::nextCommand 1]
- message "Reformatted."
- }
-
- proc S::getCommand {pos} {
-
- set pos1 [pos::math [nextLineStart $pos] - 1]
- set pat {^[^\r\n\t \}\)]}
- set posBeg "-1"
- set posEnd "-1"
- if {![catch {search -f 0 -r 1 $pat $pos1} match]} {
- set posBeg [lindex $match 0]
- set pos2 [nextLineStart $posBeg]
- if {![catch {search -f 1 -r 1 $pat $pos2} match]} {
- set posEnd [lindex $match 0]
- } else {
- set posEnd [maxPos]
- }
- # Now back up to remove empty or commented lines.
- set posEndPrev [pos::math $posEnd - 1]
- set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
- while {[regexp {^[\t ]*$} $prevLine]} {
- set posEnd [lineStart $posEndPrev]
- set posEndPrev [pos::math $posEnd - 1]
- set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
- }
- }
- return [list $posBeg $posEnd]
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ --------------------- ◊◊◊◊ #
- #
- # ◊◊◊◊ version history ◊◊◊◊ #
- #
- # modified by vers# reason
- # -------- --- ------ -----------
- # 01/28/20 cbu 1.0.1 First created S mode, based upon other modes found
- # in Alpha's distribution. Commands are based on
- # release number 3.3, taken from the "common commands"
- # as listed in Venable and Ripley's "Modern Applied
- # Statistics with S-PLUS", second edition.
- # 03/02/20 cbu 1.0.2 Minor modifications to comment handling.
- # 03/20/00 cbu 1.0.3 Minor update of keywords dictionaries.
- # Removed markFile and parseFuncs procs, because they're
- # not stable or properly worked out.
- # 04/01/00 cbu 1.0.4 Fixed a little bug with "comment box".
- # Added new preferences to allow the user to optionally
- # use $ as a Magic Character, and to enter additional
- # commands and options.
- # Removed the "Either/Ors" category, put them into arguments.
- # Added the C++ MarkFile and parseFuncs procs.
- # Added "Update Colors" proc to avoid need for a restart
- # 04/08/00 cbu 1.0.5 Unset obsolete preferences from earlier versions.
- # Added "Continue Comment" and "Electric Return Over-ride".
- # Renamed "Update Colors" to "Update Preferences".
- # Added the tcl indentation routines.
- # 04/16/00 cbu 1.1 Renamed to sMode.tcl
- # Wrote my own "Mark File" proc, replaced the C++ MarkFile.
- # Removed indentation routines, at least for now.
- # 06/22/00 cbu 1.2 "Mark File" now recognizes headings as well as commands.
- # Completions, Completions Tutorial added.
- # "Reload Completions", referenced by "Update Preferences".
- # Better support for user defined keywords.
- # Removed "Continue Comment", now global in Alpha 7.4.
- # Added command double-click for on-line help.
- # <shift, control>-<command> double-click syntax info.
- # (Foundations, at least. Ongoing project.)
- # 08/07/00 cbu 1.2.1 DblClick now looks for variable (etc) definitions
- # in current file.
- # Added message if no matching ")".
- # Mark File can mark a frequencies file.
- # Beta-version of an S-Plus menu, based on the Stata menu.
- # No Macintosh versions of S-Plus or R limit its
- # functionality ...
- # Added "s+Sig" preference to allow user to find
- # local application if necessary, in case S+/R is ever
- # ported to the Macintosh.
- # Added S::sig which returns S-Plus signature.
- # 08/28/00 cbu 1.2.2 Added some of the flag preferences to "S+/R Help" menu.
- # Added "flagFlip" to update preference bullets in menu.
- # Added "application" preference, used in menu.
- # Added "rSig" preference.
- # Added a "noHelpKey" preference, which switches the
- # "help" key binding to F8.
- # Added "Add New Commands / Arguments" to "S+/R Help" menu.
- # Added "Set S+/R Application to "S+/R Help" menu.
- # Starting to differentiate code based on platform.
- # Including a "beta message" for untested menu items.
- # 11/05/00 cbu 1.3 Added "next/prevCommand", "selectCommand", and
- # "copyCommand" procs to menu.
- # Added "S::indentLine".
- # Added "S::reformatCommand" to menu.
- # Added "S::continueCommand" to over-ride indents.
- # "S::reloadCompletions" is now obsolete.
- # "S::updatePreferences" is now obsolete.
- # "S::colorizeS" now takes care of setting all
- # keyword lists, including Scmds.
- # Cleaned up completion procs. This file never has to be
- # reloaded. (Similar cleaning up for "S::DblClick").
- # 11/16/00 cbu 2.0 New url prefs handling requires 7.4b21
- # Added "Home Page" pref, menu item.
- # Removed hook::register requireOpenWindowsHook from
- # mode declaration, put it after menu build.
- # 12/19/00 cbu 2.1 The menu proc "Add Commands" now includes an option
- # to grab all of the "extra" command from the current
- # window, using S::addWindowCommands.
- # Added "Keywords" submenu, "List Keywords" menu item.
- # Big cleanup of ::sig, ::setApplication, processing ...
- # 01/25/01 cbu 2.1.1 Bug fix for S::processSelection/File.
- # Bug fix for comment characters.
- #
-
- # ===========================================================================
- #
- # .
-
-